📌 答题前先看:物理设计三件套
- 选数据类型:每个字段问自己 —— 是数字还是文字?长度固定吗?需要多大范围?
- 定约束:主码?外码?非空?默认值?
- 建索引:主码必建;查得多的、连接的建;改得多、取值少的不建。
① 金额用 DECIMAL,绝不用 FLOAT(浮点数会丢精度)
② 身份证号、手机号用 CHAR,绝不用 INT(超出 INT 范围 + 开头 0 会丢)
③ "性别"这种取值少的字段不要建索引(区分度太低,没用)
📝 第一部分 · 概念巩固10 分钟
先用几道选择题把核心概念过一遍。
下列字段中,最适合 建立索引的是?
📖 查看答案
✅ 答案:B
分析:
A 错:性别只有男/女,区分度太低,索引基本没用
B 对:用户编号是外键 + 频繁查询条件,正是建索引的最佳场景
C 错:长文本字段不适合建普通索引(要建也得用全文索引)
D 错:频繁更新的字段建索引会拖慢更新速度
📌 口诀:"主码一定建、查得多的建、改得多的不建、取值少的不建"
下列数据类型选择,错误 的是?
📖 查看答案
✅ 错误的是:C
金额、价格、余额等"必须精确"的数值,绝对不能用 FLOAT 或 DOUBLE!
原因:浮点数在计算机里是近似存储的,会有精度误差。比如:
0.1 + 0.2 = 0.30000000000000004(不等于 0.3!)
对金额来说,1 分钱的误差日积月累就是大问题。所有金额必须用 DECIMAL(M,N),存的就是精确值。
下列字段中,最适合用 CHAR 而不是 VARCHAR 的是?
📖 查看答案
✅ 答案:B
判断口诀:"长度定 → CHAR,长度变 → VARCHAR"
① 学号永远 8 位,长度固定 → 用 CHAR(8)
② 家庭住址、商品名称、详细描述 —— 每条记录长度都不一样,用 VARCHAR 才不浪费空间
类似"长度固定"的字段:身份证号、手机号、邮政编码、银行卡号等
数据库实施阶段,第一步 应该做什么?
📖 查看答案
✅ 答案:B · 建立数据库结构
实施 5 步顺序:建立结构 → 装入数据 → 编码调试 → 试运行 → 整理文档
逻辑:先有表结构(房子盖好),才能装数据(搬家具),然后写程序连接数据库(接电接水)、试运行(住进去用一段)、最后整理文档。
下列工作 不属于 数据库 DBA 的运维任务?
📖 查看答案
✅ 答案:D
设计 E-R 图属于"概念结构设计"阶段(第 13 章),是项目开始时的工作,不是运维。
运维 4 工作:
① 转储和恢复(A 是这个)
② 维护安全性与完整性(B 是这个)
③ 监测并改善性能(C 是这个)
④ 重新组织和构造数据库
口诀:"备恢复、保安全、调性能、重结构"
💻 第二部分 · 数据类型选择实操10 分钟 · 必考
本部分是 实操题。给一组字段,自己选数据类型和约束,再对照标准答案。
为下面的"学生信息"表选择合适的数据类型和约束:
- 学号:固定 10 位数字字符串(如 "2024010001")
- 姓名:2-10 个汉字
- 性别:男 / 女
- 出生日期:年月日
- 手机号:11 位数字
- 身高:精确到小数点后 2 位(如 1.75 米)
- 个人简介:可能很长的文字描述
💡 建议:先自己写一遍答案,再点开对照。
📖 查看答案
| 字段 | 数据类型 | 约束 | 选型理由 |
|---|---|---|---|
| 学号 | CHAR(10) | 主码 | 长度固定 10 位 → CHAR;不能用 INT(开头 0 会丢,且不参与运算) |
| 姓名 | VARCHAR(20) | 非空 | 长度变化(2-10 字)→ VARCHAR;utf8mb4 一个汉字最多 4 字节,留富裕 |
| 性别 | CHAR(2) 或 TINYINT | — | CHAR(2)直接存"男/女";TINYINT用 1/2 表示更省空间 |
| 出生日期 | DATE | — | 只到日,不需要时间 → DATE 比 DATETIME 省空间 |
| 手机号 | CHAR(11) | — | ⚠️ 不能用 INT!11 位数字超过 INT 范围 |
| 身高 | DECIMAL(3,2) | — | 精确小数 → DECIMAL;3 位总长 + 2 位小数(最大 9.99 米够用) |
| 个人简介 | TEXT | — | 长文本 → TEXT;如果限制 500 字内可以用 VARCHAR(500) |
① 学号、手机号 千万不要用 INT!
② 出生日期不要用 VARCHAR 存"2000-01-01"字符串 —— 用 DATE 更标准、能比较大小
③ 身高、价格等精确小数 都用 DECIMAL,不用 FLOAT
某同学设计了一张"订单"表如下,请找出 3 处不合理 的设计并改正:
| 字段名 | 数据类型 | 说明 |
|---|---|---|
| order_id | INT | 订单编号(17 位字符) |
| amount | FLOAT | 订单金额 |
| customer_phone | INT | 客户手机号(11 位) |
| order_time | DATETIME | 下单时间 |
| status | CHAR(10) | 订单状态(待付款/已发货等) |
📖 查看答案
3 处错误:
17 位字符的订单编号超过 INT 范围。应改为 CHAR(17)(订单号格式固定)。
金额必须精确,FLOAT 会有精度误差。应改为 DECIMAL(10,2)。
11 位手机号超出 INT 范围(INT 最大约 21 亿)。应改为 CHAR(11)。
status 用 CHAR(10) 不算错,但 更好 的做法是用 ENUM 或 TINYINT。
例如:用 TINYINT 存 1/2/3 分别表示"待付款/已发货/已完成",比存中文字符串更省空间、查询更快。
🔍 第三部分 · 索引判断实操10 分钟 · 必考
本部分练习 "哪些字段该建索引"。这是必考点。
某 电商订单系统 有一张订单表,字段如下。对每个字段判断是否建索引,并说明理由:
- 订单编号:主码
- 客户编号:每次查询订单都要按客户筛选;连接客户表时常用
- 订单金额:很少作为查询条件(不会按精确金额搜订单)
- 订单状态:取值仅 5 个(待付款、已付款、已发货、已签收、已退款);经常更新
- 下单时间:经常用于"查最近一周的订单"这种范围查询
- 收货地址:很长的文本,几乎不查询
📖 查看答案
| 字段 | 建? | 理由 |
|---|---|---|
| 订单编号 | ✅ 必建 | 主码必建唯一索引(DBMS 自动建) |
| 客户编号 | ✅ 必建 | 外键 + 频繁查询/连接 —— 索引收益巨大 |
| 订单金额 | ❌ 不建 | 很少作为查询条件,建了浪费 |
| 订单状态 | ❌ 不建 | 取值少(区分度低)+ 频繁更新(维护代价高) |
| 下单时间 | ✅ 建议建 | 经常用于范围查询(如"最近一周"),索引有效 |
| 收货地址 | ❌ 不建 | 长文本 + 几乎不查 —— 建了没用 |
这张表 建议建 3 个索引:订单编号(主键自带)、客户编号、下单时间。
这就是真实电商订单表的标准做法 —— 所谓"建索引"不是越多越好,而是 "该建的建,不该建的不建"。
下面这种说法 对吗?请说明理由:
"为了让查询都快,应该给所有字段都建上索引。这样无论查什么字段都能用索引加速。"
📖 查看答案
❌ 这种说法是错的。原因有 3 个:
每个索引都是一份"目录",要占额外存储空间。10 个字段就是 10 份索引数据。
每次 INSERT / UPDATE / DELETE 都要 同时维护所有索引。索引越多,增删改越慢。
对于电商高并发系统,每秒上千次写入,索引太多会直接拖垮数据库。
查询优化器要从多个索引中选最合适的,索引太多反而 增加优化时间。
✅ 正确做法:"该建的建,不该建的不建"
① 主码必建
② 频繁出现在 WHERE 中的字段建
③ 连接(JOIN)字段建
④ 频繁更新的、取值少的、几乎不查询的字段不要建
🎯 第四部分 · 综合大题15 分钟 · 必考
本部分是 必考综合大题:给一个关系模式,完成完整的 物理设计 + 写出 CREATE TABLE。
设计一张"图书"表,要求完成 3 步:
- 设计字段名、数据类型、约束
- 写出完整的
CREATE TABLE语句 - 说明应该建哪些索引
图书(ISBN, 书名, 作者, 出版社, 出版日期, 价格, 库存量, 简介)
- ISBN:固定 13 位(如 "9787121012345")
- 书名:1~50 个字,必填
- 作者:1~30 个字,必填,经常按作者搜索
- 出版社:1~30 个字
- 出版日期:年月日
- 价格:精确小数,最大不超过 9999.99
- 库存量:整数
- 简介:可能很长的文字
📖 查看答案
第一步:物理设计表
| 字段名 | 数据类型 | 约束 | 理由 |
|---|---|---|---|
| isbn | CHAR(13) | 主码 | 长度固定 13 位 |
| book_name | VARCHAR(50) | 非空 | 长度变化 |
| author | VARCHAR(30) | 非空 | 长度变化 |
| publisher | VARCHAR(30) | — | 长度变化 |
| publish_date | DATE | — | 只要日,不要时间 |
| price | DECIMAL(6,2) | — | 精确小数;总位数 6(4 整数 + 2 小数) |
| stock | INT | 默认 0 | 整数 |
| summary | TEXT | — | 长文本 |
第二步:写出 CREATE TABLE
CREATE TABLE book (
isbn CHAR(13) NOT NULL COMMENT 'ISBN',
book_name VARCHAR(50) NOT NULL COMMENT '书名',
author VARCHAR(30) NOT NULL COMMENT '作者',
publisher VARCHAR(30) COMMENT '出版社',
publish_date DATE COMMENT '出版日期',
price DECIMAL(6,2) COMMENT '价格',
stock INT DEFAULT 0 COMMENT '库存量',
summary TEXT COMMENT '简介',
PRIMARY KEY (isbn)
);
-- 建索引
CREATE INDEX idx_author ON book(author);
第三步:索引说明
① isbn(主键自带索引) —— 主码必建
② author(手动建) —— 题目说"经常按作者搜索",索引能大幅提速
book_name、publisher、price 等字段:题目没说频繁查询,且 book_name 本身查询多用模糊匹配(LIKE '%xxx%'),普通索引帮助有限。
设计一张"借阅记录"表,要求写出完整的 CREATE TABLE 语句(含外键和索引):
借阅(借阅编号, 读者编号, ISBN, 借出日期, 应还日期, 实际归还日期)
- 借阅编号:自增整数,主码
- 读者编号:8 位字符,外键引用 reader 表
- ISBN:13 位字符,外键引用 book 表
- 借出日期、应还日期:年月日,必填
- 实际归还日期:可空(未归还时为 NULL)
- 查询场景:经常按"读者编号"查某人的借阅记录;经常按"ISBN"查某本书的借阅历史
📖 查看答案
分析:这道题的关键是 ① 自增主键 ② 外键约束 ③ 给两个外键字段都建索引(因为题目明说"经常按...查")。
CREATE TABLE borrow (
borrow_id INT AUTO_INCREMENT COMMENT '借阅编号',
reader_id CHAR(8) NOT NULL COMMENT '读者编号',
isbn CHAR(13) NOT NULL COMMENT '图书 ISBN',
borrow_date DATE NOT NULL COMMENT '借出日期',
due_date DATE NOT NULL COMMENT '应还日期',
return_date DATE COMMENT '实际归还日期,未还为 NULL',
PRIMARY KEY (borrow_id),
FOREIGN KEY (reader_id) REFERENCES reader(reader_id),
FOREIGN KEY (isbn) REFERENCES book(isbn)
);
-- 建索引(外键查询频繁,必须建)
CREATE INDEX idx_reader ON borrow(reader_id);
CREATE INDEX idx_isbn ON borrow(isbn);
① AUTO_INCREMENT 让主键自动 +1,省去手动给编号的麻烦
② FOREIGN KEY 加外键约束,保证 reader_id 和 isbn 必须在被引用表中存在
③ return_date 不加 NOT NULL —— 因为未归还时就是 NULL
④ MySQL 8.0 中 外键字段会自动建索引,但显式建一份更稳妥(兼容旧版本)
📝 复习重点回顾
通过本次练习,你应该已经:
- ✅ 能为常见字段选择 合适的数据类型(CHAR/VARCHAR/INT/DECIMAL/DATE/DATETIME/TEXT)
- ✅ 能判断 哪些字段该建索引、哪些不该建
- ✅ 能根据关系模式 写出完整的 CREATE TABLE(含主键、外键、索引)
- ✅ 知道数据库实施 5 步骤、运维 4 工作的考点
按出现频率排序:
- 写出 CREATE TABLE 语句:综合大题,分值最高
- 数据类型选择题:常考易错(手机号/金额/CHAR vs VARCHAR)
- 索引判断题:哪个字段该建索引
- 实施 5 步骤、运维 4 工作:填空 / 简答
- 数据库设计 6 阶段顺序:填空
① 数据类型:长度定→CHAR,长度变→VARCHAR;金额→DECIMAL;号码→CHAR
② 索引:主码一定建,查得多的建,改得多的不建,取值少的不建
③ 设计 6 阶段:需 概 逻 物 实 维(需求-概念-逻辑-物理-实施-运维)